package algorithm;

import bean.Ant;

import java.util.ArrayList;
import java.util.List;

/**
 * @author letere
 * @create 2020-12-25 9:30
 */
public class ACO {
    List<Integer> citys = new ArrayList<Integer>(); //城市集合
    private double[][] pheromoneMatrix; //信息素矩阵
    private int[][] distanceMatrix; //距离矩阵

    private  int[][] timeMatrix; //时间矩阵
    private int times; //运行次数
    private int antQuantity; // 蚂蚁数量

    private List<Integer> bestRoute; //最佳路线
    private Integer bestLength = -1; //最佳距离

    private Integer wholeTime = 0; //总时间



    //构造器
    public ACO(List<Integer> citys, double[][] pheromoneMatrix, int[][] distanceMatrix,int[][] timeMatrix, int times, int antQuantity) {
        this.citys = citys;
        this.pheromoneMatrix = pheromoneMatrix;
        this.distanceMatrix = distanceMatrix;
        this.times = times;
        this.antQuantity = antQuantity;
        this.timeMatrix = timeMatrix;
    }

    /**
     * 更新信息素
     * @param ants 蚂蚁群
     */
    private void update(List<Ant> ants) {
        //信息素挥发
        double volatilizationRate = 0.5; //挥发率
        for(int i=0; i<citys.size(); i++) {
            for(int j=0; j<citys.size(); j++) {
                pheromoneMatrix[i][j] = pheromoneMatrix[i][j] * (1.0-volatilizationRate);
            }
        }
        //信息素新增
        for(Ant ant : ants) {
            List<Integer> route = ant.getRoute();
            for(int i=0; i<route.size()-1; i++){
                pheromoneMatrix[route.get(i)-1][route.get(i+1)-1] += 1.0 / ant.getRouteLength();
            }
        }
    }

    /**
     * 记录最佳路径和最佳距离
     */
    private void recordBest(List<Ant> ants) {
        //给bestLength赋予初始值
        if(bestLength == -1.0) {
            bestLength = ants.get(0).getRouteLength();
            bestRoute = ants.get(0).getRoute();
            wholeTime = ants.get(0).getRouteTime();



        }
        //遍历比较最佳
        for(Ant ant : ants) {
            if(bestLength < ant.getRouteLength()) {
                bestLength = ant.getRouteLength();
                bestRoute = ant.getRoute();
                wholeTime = ant.getRouteTime();
                }
            }
        }

    /**
     * 运行蚁群优化算法
     */
    private void runAlgorithm(){
        List<Ant> ants = new ArrayList<Ant>();
        for(int i=0; i<antQuantity; i++){
            //复制城市集合(集合为地址引用，为了不影响原参数，复制一个新集合)
            List<Integer> cityCopy = new ArrayList<Integer>();
            for (Integer city : citys) {
                cityCopy.add(city);
            }
            //创建蚂蚁，并开始旅行
            Ant ant = new Ant(cityCopy, pheromoneMatrix, distanceMatrix,timeMatrix);
            ant.tour(); //蚂蚁开始旅行
            ants.add(ant);
        }

        update(ants); //更新信息素
        recordBest(ants); //记录最佳路线与距离
    }

    /**
     * 多次运行蚁群优化算法
     */
    public void run() {
            for(int i=0; i<times; i++){
                runAlgorithm();
            }
    }

    /**
     * 获取最佳路线
     */
    public List<Integer> getBestRoute() {
        return bestRoute;
    }

    /**
     * 获取最佳距离
     */
    public Integer getBestLength() {
        return bestLength;
    }
    /**
     * 获取最佳时间
     */
    public Integer getWholeTime(){
        return wholeTime;
    }
}
